package com.qing.springcloud.service.impl;

import cn.hutool.core.date.DateUtil;
import com.qing.springcloud.common.ChatGroupStatusEnum;
import com.qing.springcloud.common.GroupApplicationStatusEnum;
import com.qing.springcloud.common.GroupMemberRoleEnum;
import com.qing.springcloud.common.GroupMemberStatusEnum;
import com.qing.springcloud.dao.ChatGroupDao;
import com.qing.springcloud.dao.GroupApplicationDao;
import com.qing.springcloud.dao.GroupMemberDao;
import com.qing.springcloud.dao.UserDao;
import com.qing.springcloud.dto.group.ChatGroupDTO;
import com.qing.springcloud.dto.group.GroupApplicationHandleDTO;
import com.qing.springcloud.dto.group.GroupCreateDTO;
import com.qing.springcloud.dto.group.GroupMemberDTO;
import com.qing.springcloud.entity.ChatGroup;
import com.qing.springcloud.entity.GroupApplication;
import com.qing.springcloud.entity.GroupMember;
import com.qing.springcloud.exception.BusinessException;
import com.qing.springcloud.notification.GroupJoinNotification;
import com.qing.springcloud.notification.GroupJoinRequestNotification;
import com.qing.springcloud.notification.GroupKickNotification;
import com.qing.springcloud.utils.EnumUtils;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import com.qing.springcloud.service.ChatGroupService;
import org.springframework.amqp.rabbit.core.RabbitTemplate;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;

import java.util.Date;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

/**
 * 群组表
服务接口实现
 *
 * @author zhipeng.cao
 * @since 2025-07-09 20:09:50
 * @description 由 Mybatisplus Code Generator 创建
 */
@Slf4j
@RequiredArgsConstructor
@Service
public class ChatGroupServiceImpl implements ChatGroupService {
    private final ChatGroupDao chatGroupDao;
    private final GroupMemberDao groupMemberDao;
    private final GroupApplicationDao groupApplicationDao;
    private final UserDao userDao;
    private final RabbitTemplate rabbitTemplate;
    private  final String EXCHANGE_NAME = "group-exchange";
    @Override
    @Transactional
    public ChatGroupDTO createGroup(GroupCreateDTO dto) {
        ChatGroup group = new ChatGroup();
        group.setGroupName(dto.getGroupName());
        group.setCreatorId(dto.getCreatorId());
        chatGroupDao.save(group);

        // 添加创建者为群主
        addGroupMember(group.getId(), dto.getCreatorId(), GroupMemberRoleEnum.OWNER);

        // 添加初始成员
        for (Long userId : dto.getMemberIds()) {
            if (!userId.equals(dto.getCreatorId())) {
                addGroupMember(group.getId(), userId, GroupMemberRoleEnum.MEMBER);
            }
        }

        return convertToDTO(group);
    }

    @Override
    @Transactional
    public void joinGroup(Long userId, Long groupId, String message) {
        if (groupMemberDao.existsByGroupIdAndUserId(groupId, userId)) {
            throw new BusinessException("已在群聊中");
        }

        GroupApplication application = new GroupApplication();
        application.setGroupId(groupId);
        application.setApplicantId(userId);
        application.setApplicantMsg(message);
        groupApplicationDao.save(application);

        // 通知群管理员
        List<Long> adminIds = groupMemberDao.findAdminIdsByGroupId(groupId);
        for (Long adminId : adminIds) {
            GroupJoinRequestNotification notification = GroupJoinRequestNotification.builder()
                    .applicationId(application.getId())
                    .groupId(groupId)
                    .userId(userId)
                    .userName(userDao.getUsername(userId))
                    .message(message)
                    .build();

            rabbitTemplate.convertAndSend(EXCHANGE_NAME, "group-join-request." + adminId, notification);
        }
    }

    @Override
    @Transactional
    public void handleGroupJoinRequest(GroupApplicationHandleDTO dto) {
        GroupApplication application = groupApplicationDao.findById(dto.getApplicationId())
                .orElseThrow(() -> new BusinessException("申请不存在"));

        // 验证操作权限
        GroupMember operator = groupMemberDao.findByGroupIdAndUserId(
                        application.getGroupId(), dto.getOperatorId())
                .orElseThrow(() -> new BusinessException("无权操作"));

        if (isAdminOrOwner(operator.getRole())) {
            throw new BusinessException("需要管理员以上权限");
        }

        application.setStatus(dto.getStatus());
        application.setHandledBy(dto.getOperatorId());
        application.setUpdatedAt(DateUtil.date());
        groupApplicationDao.updateById(application);

        if (EnumUtils.equals(GroupApplicationStatusEnum.APPROVED,dto.getStatus() )) {
            addGroupMember(application.getGroupId(), application.getApplicantId(), GroupMemberRoleEnum.MEMBER);

            // 发送加入通知
            rabbitTemplate.convertAndSend(EXCHANGE_NAME, "group-join." + application.getApplicantId(),
                    new GroupJoinNotification(application.getGroupId()));
        }
    }

    @Override
    @Transactional
    public void leaveGroup(Long userId, Long groupId) {
        GroupMember member = groupMemberDao.findByGroupIdAndUserId(groupId, userId)
                .orElseThrow(() -> new BusinessException("不在群聊中"));

        // 如果是群主退出，需要转移群主
        if (EnumUtils.equals(GroupMemberRoleEnum.OWNER,member.getRole())) {
            transferGroupOwnership(groupId, userId);
        }

        member.setStatus(GroupMemberStatusEnum.EXITED.getCode());
        groupMemberDao.updateById(member);
    }

    private void transferGroupOwnership(Long groupId, Long oldOwnerId) {
        // 找到活跃的管理员作为新群主
        Optional<GroupMember> newOwnerOpt = groupMemberDao.findActiveAdminInGroup(groupId, oldOwnerId);

        if (newOwnerOpt.isPresent()) {
            GroupMember newOwner = newOwnerOpt.get();
            newOwner.setRole(GroupMemberRoleEnum.OWNER.getCode());
            groupMemberDao.updateById(newOwner);
        } else {
            // 没有管理员则随机选择普通成员
            Optional<GroupMember> randomMember = groupMemberDao.findActiveNormalMemberInGroup(groupId, oldOwnerId);

            if (randomMember.isPresent()) {
                GroupMember newOwner = randomMember.get();
                newOwner.setRole(GroupMemberRoleEnum.OWNER.getCode());
                groupMemberDao.updateById(newOwner);
            } else {
                // 群里没有其他成员，解散群组
                chatGroupDao.updateStatus(groupId, ChatGroupStatusEnum.DELETED.getCode());
            }
        }
    }

    @Override
    @Transactional
    public void kickGroupMember(Long operatorId, Long groupId, Long userId) {
        // 验证操作者权限
        GroupMember operator = groupMemberDao.findByGroupIdAndUserId(groupId, operatorId)
                .orElseThrow(() -> new BusinessException("操作者不在群中"));

        if (isAdminOrOwner(operator.getRole())) {
            throw new BusinessException("需要管理员以上权限");
        }

        // 验证被踢成员
        GroupMember member = groupMemberDao.findByGroupIdAndUserId(groupId, userId)
                .orElseThrow(() -> new BusinessException("目标用户不在群中"));

        // 不能踢群主
        if (EnumUtils.equals(member.getRole(), GroupMemberRoleEnum.OWNER)) {
            throw new BusinessException("不能踢出群主");
        }

        // 管理员不能踢其他管理员（群主可以）
        if (EnumUtils.equals(member.getRole(),GroupMemberRoleEnum.ADMIN) &&
                !EnumUtils.equals(operator.getRole(),GroupMemberRoleEnum.OWNER)) {
            throw new BusinessException("只有群主可以踢出管理员");
        }

        member.setStatus(GroupMemberStatusEnum.KICKED.getCode());
        groupMemberDao.updateById(member);

        // 发送被踢通知
        rabbitTemplate.convertAndSend(EXCHANGE_NAME, "group-kicked." + userId, new GroupKickNotification(groupId));
    }

     private  boolean isAdminOrOwner(Integer role){
         return !EnumUtils.equals(role, GroupMemberRoleEnum.ADMIN) && !EnumUtils.equals(role, GroupMemberRoleEnum.OWNER);
     }

    @Override
    public List<GroupMemberDTO> getGroupMembers(Long groupId) {
        List<GroupMember> groupMemberList=groupMemberDao.findByGroupId(groupId,GroupMemberStatusEnum.NORMAL.getCode());
        return groupMemberList.stream().map(this::convertToMemberDTO).collect(Collectors.toList());
    }

    @Override
    public List<Long> getGroupMemberIds(Long groupId) {
        List<GroupMember> groupMemberList=groupMemberDao.findByGroupId(groupId,GroupMemberStatusEnum.NORMAL.getCode());
        return Optional.ofNullable(groupMemberList).map(list->list.stream().map(GroupMember::getUserId).toList()).orElse(null);
    }

    private void addGroupMember(Long groupId, Long userId, GroupMemberRoleEnum groupMemberRoleEnum) {
        GroupMember member = new GroupMember();
        member.setGroupId(groupId);
        member.setUserId(userId);
        member.setRole(groupMemberRoleEnum.getCode());
        member.setStatus(GroupMemberStatusEnum.NORMAL.getCode());
        groupMemberDao.save(member);
    }

    private ChatGroupDTO convertToDTO(ChatGroup group) {
        return ChatGroupDTO.builder()
                .id(group.getId())
                .groupName(group.getGroupName())
                .creatorId(group.getCreatorId())
                .avatar(group.getAvatar())
                .build();
    }

    private GroupMemberDTO convertToMemberDTO(GroupMember member) {
        return GroupMemberDTO.builder()
                .userId(member.getUserId())
                .role(member.getRole())
                .remarkName(member.getRemarkName())
                .build();
    }
}